
package com.voto.sunflower.activity.me;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.lang.ref.WeakReference;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;

import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageInfo;
import android.net.Uri;
import android.os.AsyncTask;

public class Updater {

    private static boolean mbUpdating = false;
    private static UpgradeTask mTask;

    public static final void update(Context context, UpdateCallback cb, String version, String url) {
        if (mbUpdating) return;
        mbUpdating = true;
        String filePath = context.getCacheDir().getPath() + File.separator + "updater.apk";
        File file = new File(filePath);
        if (file.exists()) {
            PackageInfo packInfo = context.getPackageManager().getPackageArchiveInfo(filePath, 0);
            if (version.equals(packInfo.versionName)) {
                install(context, file);
                mbUpdating = false;
                cb.onUpdateReady();
                return;
            }
            file.delete();
        }
        mTask = new UpgradeTask(context, cb);
        mTask.execute(version, url, filePath);
    }

    public static void cancel() {
        mbUpdating = false;
        if (null != mTask) mTask.cancel(true);
    }

    private static void install(Context context, File file) {
        Intent intent = new Intent(Intent.ACTION_VIEW);
        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        intent.setDataAndType(Uri.fromFile(file), "application/vnd.android.package-archive");
        context.startActivity(intent);
    }

    private static boolean save(UpgradeTask task, String url, OutputStream os) {
        URL myFileUrl;
        try {
            myFileUrl = new URL(url);
        } catch (MalformedURLException e) {
            // e.printStackTrace();
            return false;
        }

        byte[] b = new byte[2048];

        HttpURLConnection conn = null;
        InputStream is = null;
        try {
            conn = (HttpURLConnection) myFileUrl.openConnection();
            conn.connect();
            int total = conn.getContentLength();
            int position = 0;
            is = conn.getInputStream();
            int len = 0;
            while ((len = is.read(b, 0, 2048)) != -1) {
                os.write(b, 0, len);
                if (total > 0) {
                    position += len;
                    task.updateProcess(position * 100 / total);
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
            return false;
        } finally {
            if (null != is) {
                try {
                    is.close();
                } catch (IOException e) {
                }
            }
            if (null != conn) conn.disconnect();
        }

        return true;
    }

    private static class UpgradeTask extends AsyncTask<String, Integer, File> {

        private final WeakReference<Context> mWRContext;
        private final WeakReference<UpdateCallback> mWRCallback;

        UpgradeTask(Context context, UpdateCallback cb) {
            mWRContext = new WeakReference<Context>(context);
            mWRCallback = new WeakReference<UpdateCallback>(cb);
        }

        @Override
        protected void onPreExecute() {
        }

        final void updateProcess(int percent) {
            publishProgress(percent);
        }

        @Override
        protected File doInBackground(String... params) {
            String version = params[0];
            String url = params[1];
            String path = params[2];
            File file = new File(path);
            OutputStream fos;
            try {
                fos = new FileOutputStream(file);
            } catch (FileNotFoundException e) {
                e.printStackTrace();
                return null;
            }
            boolean bRet = save(this, url, fos);
            try {
                fos.flush();
                fos.close();
            } catch (IOException e) {
                e.printStackTrace();
                bRet = false;
            }
            if (!bRet) {
                file.delete();
                return null;
            }
            file.setReadable(true, false);
            // verify apk
            Context ctx = mWRContext.get();
            if (null == ctx) return null;
            PackageInfo packInfo = ctx.getPackageManager().getPackageArchiveInfo(file.getAbsolutePath(), 0);
            if (null == packInfo) return null;
            if (!version.equals(packInfo.versionName)) return null;
            return file;
        }

        @Override
        protected void onProgressUpdate(Integer... values) {
            UpdateCallback cb = mWRCallback.get();
            if (null != cb) cb.onUpdatePercent(values[0]);
        }

        @Override
        protected void onPostExecute(File file) {
            mbUpdating = false;
            UpdateCallback cb = mWRCallback.get();
            if (null == cb) return;
            if (null == file) {
                cb.onUpdateFail("");
                return;
            }
            Context ctx = mWRContext.get();
            if (null == ctx) return;
            install(ctx, file);
            cb.onUpdateReady();
        }
    }

    public interface UpdateCallback {

        void onUpdateFail(String reason);

        void onUpdatePercent(int percent);

        void onUpdateReady();
    }
}
